package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.common.Constant;
import com.example.demo.dao.BalanceRepository;
import com.example.demo.model.entity.BalanceModel;
import com.example.demo.model.entity.ProductModel;
import com.example.demo.model.entity.UserModel;
import com.example.demo.model.response.ExportBalance;
import com.example.demo.service.impl.BalanceService;
import com.example.demo.service.impl.ProductService;
import com.example.demo.service.impl.UserService;
import com.example.demo.util.excel.GeneralExcelPoi;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Decoder;

import javax.persistence.criteria.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
@RequestMapping(value = Constant.API_VERSION + "/balance")
public class BalanceController {

    @Autowired
    UserService userService;

    @Autowired
    BalanceService balanceService;

    @Autowired
    ProductService productService;

    @RequestMapping(value = "/action/add", method = RequestMethod.POST)
    @ResponseBody
    public void add(@RequestHeader("Authorization") String token, @RequestBody BalanceModel model) throws Exception {
        BASE64Decoder decoder = new BASE64Decoder();
        String currentUid = new String(decoder.decodeBuffer(token), "UTF-8");
        UserModel user = userService.getByUid(currentUid);
        if (user.getRole() == Constant.Role.USER.getRoleCode()) {
            throw new RuntimeException(MessageFormat.format(Constant.ERROR_FORMAT, 403, "权限不足"));
        }
        UserModel operaUser = userService.getByUid(model.getUserId());
        operaUser.setBalance(operaUser.getBalance().add(model.getBalance()));
        model.setCreateTime(System.currentTimeMillis());
        model.setBalance(model.getBalance());
        model.setMoney(operaUser.getBalance());
        model.setBalanceDesc("充值");
        model.setBalanceId(UUID.randomUUID().toString());
        model.setUserId(model.getUserId());
        model.setHandlerUid(user.getUserId());
        model.setHandlerUsername(user.getUserName());
        balanceService.save(model);
        userService.save(operaUser);

    }

    @RequestMapping(value = "/action/cost", method = RequestMethod.POST)
    @ResponseBody
    public void cost(@RequestHeader("Authorization") String token, @RequestBody BalanceModel model) throws Exception {
        BASE64Decoder decoder = new BASE64Decoder();
        String currentUid = new String(decoder.decodeBuffer(token), "UTF-8");
        UserModel user = userService.getByUid(currentUid);
        if (user.getRole() == Constant.Role.USER.getRoleCode()) {
            throw new RuntimeException(MessageFormat.format(Constant.ERROR_FORMAT, 403, "权限不足"));
        }
        UserModel operaUser = userService.getByUid(model.getUserId());
        if (operaUser.getBalance().compareTo(model.getBalance()) == -1) {
            throw new RuntimeException(MessageFormat.format(Constant.ERROR_FORMAT, 400, "余额不足"));
        }
        if (StringUtils.isNotEmpty(model.getProductId())) {
            ProductModel product = productService.getById(model.getProductId());
            if (product != null) {
                model.setProductId(product.getProductName());
            }
        }
        operaUser.setBalance(operaUser.getBalance().subtract(model.getBalance()));
        model.setCreateTime(System.currentTimeMillis());
        model.setBalance(model.getBalance());
        model.setMoney(operaUser.getBalance());
        model.setBalanceDesc("消费");
        model.setBalanceId(UUID.randomUUID().toString());
        model.setUserId(model.getUserId());
        model.setHandlerUid(user.getUserId());
        model.setHandlerUsername(user.getUserName());
        balanceService.save(model);
        userService.save(operaUser);
    }

    @RequestMapping(value = "", method = RequestMethod.GET)
    @ResponseBody
    public JSONObject getBalanceList(@RequestHeader("Authorization") String token, @RequestParam(value = "user_id", defaultValue = "") final String userId, @RequestParam(value = "page_size", defaultValue = "10") String pageSize,
                                     @RequestParam(value = "page_number", defaultValue = "1") String pageNumber, @RequestParam(value = "start", defaultValue = "") final String start,
                                     @RequestParam(value = "end", defaultValue = "") final String end, @RequestParam(value = "balance_desc", defaultValue = "") final String balanceDesc) throws Exception {

        BASE64Decoder decoder = new BASE64Decoder();
        String currentUid = new String(decoder.decodeBuffer(token), "UTF-8");
        Page<BalanceModel> balancePage = balanceService.getBalancePage(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicateList = new ArrayList<>();
                if (StringUtils.isNotEmpty(userId)) {
                    Path<String> userIdPath = root.get("userId");
                    predicateList.add(criteriaBuilder.equal(userIdPath, userId));
                }

                if (StringUtils.isNotEmpty(start)) {
                    Path<Long> createTime = root.get("createTime");
                    predicateList.add(criteriaBuilder.lessThanOrEqualTo(createTime, Long.valueOf(end)));
                    predicateList.add(criteriaBuilder.greaterThanOrEqualTo(createTime, Long.valueOf(start)));
                }

                if (StringUtils.isNotEmpty(balanceDesc)) {
                    Path<String> desc = root.get("balanceDesc");
                    predicateList.add(criteriaBuilder.equal(desc, balanceDesc.equals("1") ? "充值" : "消费"));
                }

                criteriaQuery.where(predicateList.toArray(new Predicate[predicateList.size()]));
                return null;
            }
        }, new PageRequest(Integer.valueOf(pageNumber) - 1, Integer.valueOf(pageSize), new Sort(Sort.Direction.DESC, "createTime")));


        JSONObject result = new JSONObject();
        result.put("total", balancePage.getTotalElements());
        result.put("items", balancePage.getContent());
        result.put("cost", balanceService.sum(start, end, "消费"));
        result.put("get", balanceService.sum(start, end, "充值"));
        return result;
    }


    @RequestMapping(value = "/action/export", method = RequestMethod.GET)
    @ResponseBody
    public void export(@RequestParam(value = "user_id", defaultValue = "") final String userId,
                       @RequestParam(value = "start", defaultValue = "") final String start,
                       @RequestParam(value = "end", defaultValue = "") final String end,
                       @RequestParam(value = "balance_desc", defaultValue = "") final String balanceDesc,
                       HttpServletResponse response) throws Exception {

        BASE64Decoder decoder = new BASE64Decoder();
//        String currentUid = new String(decoder.decodeBuffer(token), "UTF-8");
        List<BalanceModel> balanceAll = balanceService.getBalanceAll(new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicateList = new ArrayList<>();
                if (StringUtils.isNotEmpty(userId)) {
                    Path<String> userIdPath = root.get("userId");
                    predicateList.add(criteriaBuilder.equal(userIdPath, userId));
                }

                if (StringUtils.isNotEmpty(start)) {
                    Path<Long> createTime = root.get("createTime");
                    predicateList.add(criteriaBuilder.lessThanOrEqualTo(createTime, Long.valueOf(end)));
                    predicateList.add(criteriaBuilder.greaterThanOrEqualTo(createTime, Long.valueOf(start)));
                }

                if (StringUtils.isNotEmpty(balanceDesc)) {
                    Path<String> desc = root.get("balanceDesc");
                    predicateList.add(criteriaBuilder.equal(desc, balanceDesc.equals("1") ? "充值" : "消费"));
                }

                criteriaQuery.where(predicateList.toArray(new Predicate[predicateList.size()]));
                return null;
            }
        });
        String time = "yyyy-MM-dd";
        String time1 = "yyyy-MM-dd HH:mm:ss";
        SimpleDateFormat format = new SimpleDateFormat(time);
        SimpleDateFormat format1 = new SimpleDateFormat(time1);
        if (CollectionUtils.isNotEmpty(balanceAll)) {
            List<ExportBalance> result = new ArrayList<>();
            for (BalanceModel b : balanceAll) {
                ExportBalance eb = new ExportBalance();
                eb.setDate(format1.format(new Date()));
                eb.setAmount(b.getBalance().stripTrailingZeros().toPlainString());
                eb.setBalance(b.getMoney().stripTrailingZeros().toPlainString());
                eb.setProduct(b.getProductId());
                eb.setUsername(b.getUser().getUserName());
                eb.setHandler(b.getHandlerUsername());
                eb.setType(b.getBalanceDesc());
                result.add(eb);
            }
            List<String> head = new ArrayList<>();
            head.add("日期");
            head.add("类型");
            head.add("金额（元）");
            head.add("余额（元）");
            head.add("产品");
            head.add("会员");
            head.add("操作人员");
            GeneralExcelPoi poi = new GeneralExcelPoi();
            poi.exportExcel(response, result, head, format.format(new Date()) + "_数据报表");
        }

    }


}
